package com.joyxy.spider.mapscript;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 地图脚本解析器
 * 脚本格式：[提示]$[保留位]$[地图及命令信息]$[保留位]
 */
public class MapScript {
    /** 提示信息 */
    private String hint;
    /** 第一个保留位 */
    private String reserved1;
    /** 地图及命令信息 */
    private String mapData;
    /** 第二个保留位 */
    private String reserved2;
    /** 解析后的脚本层列表 */
    private List<ScriptLayer> layers;
    
    public MapScript() {
        this.layers = new ArrayList<>();
    }
    
    /**
     * 从文件加载并解析脚本
     */
    public static MapScript loadFromFile(String filePath) throws IOException {
        MapScript script = new MapScript();
        
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            StringBuilder content = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
            
            script.parseScript(content.toString());
        }
        
        return script;
    }
    
    /**
     * 从字符串解析脚本
     */
    public static MapScript parseFromString(String scriptContent) {
        MapScript script = new MapScript();
        script.parseScript(scriptContent);
        return script;
    }
    
    /**
     * 解析脚本内容
     */
    private void parseScript(String scriptContent) {
        if (scriptContent == null || scriptContent.trim().isEmpty()) {
            return;
        }
        
        // 先处理换行符，统一为空格分隔
        String normalizedContent = scriptContent.replace("\n", "").replace("\r", "");
        
        // 按$分割脚本的四个部分
        String[] parts = normalizedContent.split("\\$", -1); // -1保证空字符串也被保留
        
        if (parts.length >= 1) {
            this.hint = parts[0].trim();
        }
        if (parts.length >= 2) {
            this.reserved1 = parts[1].trim();
        }
        if (parts.length >= 3) {
            this.mapData = parts[2].trim();
            parseMapData(this.mapData);
        }
        if (parts.length >= 4) {
            this.reserved2 = parts[3].trim();
        }
    }
    
    /**
     * 解析地图及命令信息
     * 格式：[地图层1范围及相应命令]#[地图层2范围及相应命令]#
     */
    private void parseMapData(String mapData) {
        if (mapData == null || mapData.trim().isEmpty()) {
            return;
        }
        
        // 按#分割各个地图层
        String[] layerStrings = mapData.split("#");
        
        for (String layerString : layerStrings) {
            if (layerString.trim().isEmpty()) {
                continue;
            }
            
            ScriptLayer layer = parseLayer(layerString.trim());
            if (layer != null) {
                layers.add(layer);
            }
        }
    }
    
    /**
     * 解析单个地图层
     * 格式：Map%XMin%XMax%YMin%YMax%OP1+OP2+...
     */
    private ScriptLayer parseLayer(String layerString) {
        if (layerString == null || layerString.trim().isEmpty()) {
            return null;
        }
        
        // 按%分割层信息
        String[] parts = layerString.split("%");
        
        if (parts.length < 6) {
            System.err.println("层格式错误，至少需要6个部分: " + layerString);
            return null;
        }
        
        try {
            int mapId = Integer.parseInt(parts[0]);
            int xMin = Integer.parseInt(parts[1]);
            int xMax = Integer.parseInt(parts[2]);
            int yMin = Integer.parseInt(parts[3]);
            int yMax = Integer.parseInt(parts[4]);
            
            ScriptLayer layer = new ScriptLayer(mapId, xMin, xMax, yMin, yMax);
            
            // 解析操作命令（第6部分及以后）
            StringBuilder operationsStr = new StringBuilder();
            for (int i = 5; i < parts.length; i++) {
                if (i > 5) {
                    operationsStr.append("%");
                }
                operationsStr.append(parts[i]);
            }
            
            parseOperations(layer, operationsStr.toString());
            
            return layer;
        } catch (NumberFormatException e) {
            System.err.println("层坐标格式错误: " + layerString + ", 错误: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 解析操作命令
     * 格式：OP1+OP2+... 其中每个OP格式为：操作数|参数1/参数2/...
     */
    private void parseOperations(ScriptLayer layer, String operationsString) {
        if (operationsString == null || operationsString.trim().isEmpty()) {
            return;
        }
        
        // 按+分割各个操作
        String[] operationStrings = operationsString.split("\\+");
        
        for (String operationString : operationStrings) {
            if (operationString.trim().isEmpty()) {
                continue;
            }
            
            ScriptOperation operation = parseOperation(operationString.trim());
            if (operation != null) {
                layer.addOperation(operation);
            }
        }
    }
    
    /**
     * 解析单个操作
     * 格式：操作数|参数1/参数2/参数3/.../参数N
     */
    private ScriptOperation parseOperation(String operationString) {
        if (operationString == null || operationString.trim().isEmpty()) {
            return null;
        }
        
        // 按|分割操作数和参数
        String[] parts = operationString.split("\\|");
        
        if (parts.length < 1) {
            System.err.println("操作格式错误: " + operationString);
            return null;
        }
        
        try {
            int operationType = Integer.parseInt(parts[0]);
            
            int[] parameters = null;
            if (parts.length > 1 && !parts[1].trim().isEmpty()) {
                String[] paramStrings = parts[1].split("/");
                parameters = new int[paramStrings.length];
                
                for (int i = 0; i < paramStrings.length; i++) {
                    parameters[i] = Integer.parseInt(paramStrings[i].trim());
                }
            }
            
            return new ScriptOperation(operationType, parameters);
        } catch (NumberFormatException e) {
            System.err.println("操作参数格式错误: " + operationString + ", 错误: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 根据坐标查找适用的脚本层
     */
    public ScriptLayer findLayerByPosition(int x, int y) {
        for (ScriptLayer layer : layers) {
            if (layer.isInRange(x, y)) {
                return layer;
            }
        }
        return null;
    }
    
    /**
     * 根据坐标查找适用的操作命令
     */
    public List<ScriptOperation> findOperationsByPosition(int x, int y) {
        List<ScriptOperation> result = new ArrayList<>();
        
        ScriptLayer layer = findLayerByPosition(x, y);
        if (layer != null) {
            for (ScriptOperation operation : layer.getOperations()) {
                // 对于有区域限制的操作，检查是否在操作区域内
                if (operation.getParameterCount() >= 4) {
                    if (operation.isInOperationArea(x, y)) {
                        result.add(operation);
                    }
                } else {
                    // 对于没有区域限制的操作，直接添加
                    result.add(operation);
                }
            }
        }
        
        return result;
    }
    
    /**
     * 获取指定地图ID的所有层
     */
    public List<ScriptLayer> getLayersByMapId(int mapId) {
        List<ScriptLayer> result = new ArrayList<>();
        for (ScriptLayer layer : layers) {
            if (layer.getMapId() == mapId) {
                result.add(layer);
            }
        }
        return result;
    }
    
    /**
     * 执行整个脚本的所有层
     */
    public void execute() {
        System.out.println("开始执行脚本: " + hint);
        System.out.println("总共需要执行 " + layers.size() + " 个层");
        
        for (int i = 0; i < layers.size(); i++) {
            ScriptLayer layer = layers.get(i);
            try {
                System.out.println("\n=== 执行第 " + (i + 1) + " 层 ===");
                layer.execute();
            } catch (Exception e) {
                System.err.println("执行第 " + (i + 1) + " 层失败: " + e.getMessage());
            }
        }
        
        System.out.println("\n脚本执行完成: " + hint);
    }
    
    /**
     * 执行指定坐标处的所有适用操作
     */
    public void executeAtPosition(int x, int y) {
        System.out.println("在坐标(" + x + "," + y + ")执行脚本操作");
        
        ScriptLayer layer = findLayerByPosition(x, y);
        if (layer != null) {
            System.out.println("找到适用层: " + layer);
            layer.executeForPosition(x, y);
        } else {
            System.out.println("坐标(" + x + "," + y + ")不在任何层范围内，无操作可执行");
        }
    }
    
    /**
     * 执行指定地图ID的所有层
     */
    public void executeForMap(int mapId) {
        System.out.println("执行地图 " + mapId + " 的所有层");
        
        List<ScriptLayer> mapLayers = getLayersByMapId(mapId);
        if (mapLayers.isEmpty()) {
            System.out.println("地图 " + mapId + " 没有找到任何层");
            return;
        }
        
        System.out.println("地图 " + mapId + " 共有 " + mapLayers.size() + " 个层");
        for (int i = 0; i < mapLayers.size(); i++) {
            ScriptLayer layer = mapLayers.get(i);
            try {
                System.out.println("\n--- 执行地图 " + mapId + " 第 " + (i + 1) + " 层 ---");
                layer.execute();
            } catch (Exception e) {
                System.err.println("执行地图 " + mapId + " 第 " + (i + 1) + " 层失败: " + e.getMessage());
            }
        }
    }
    
    // Getter and Setter methods
    public String getHint() {
        return hint;
    }
    
    public void setHint(String hint) {
        this.hint = hint;
    }
    
    public String getReserved1() {
        return reserved1;
    }
    
    public void setReserved1(String reserved1) {
        this.reserved1 = reserved1;
    }
    
    public String getMapData() {
        return mapData;
    }
    
    public void setMapData(String mapData) {
        this.mapData = mapData;
    }
    
    public String getReserved2() {
        return reserved2;
    }
    
    public void setReserved2(String reserved2) {
        this.reserved2 = reserved2;
    }
    
    public List<ScriptLayer> getLayers() {
        return layers;
    }
    
    public void setLayers(List<ScriptLayer> layers) {
        this.layers = layers;
    }
    
    @Override
    public String toString() {
        return String.format("MapScript{hint='%s', layers=%d}", 
                hint != null ? hint : "", layers.size());
    }
}
